package cmpp;

import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.demo.jfinal.model.ApiDownstream;
import com.demo.jfinal.redis.Redis;

import cmpp.netty.NettyCommandHandler;
import cmpp.netty.SocketChannelMap;
import cmpp.netty.UtilsUtils;
import cmpp.pdu.ActiveTest;
import cmpp.pdu.Cancel;
import cmpp.pdu.CmppPDU;
import cmpp.pdu.Connect;
import cmpp.pdu.Deliver;
import cmpp.pdu.Query;
import cmpp.pdu.Submit;
import cmpp.pdu.Terminate;
import cmpp.validate.ClientValidateUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;

/**
 * Created by ddouble on 2017/6/30.
 */
public class CmppServerHandler extends ChannelInboundHandlerAdapter {

	static protected Logger logger = Logger.getLogger(CmppServerHandler.class.getName());
	private String clientId;

	private static SocketChannelMap socketChannelMap = new SocketChannelMap();

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		socketChannelMap.remove((SocketChannel) ctx.channel());
		logger.info("客户:" + clientId + "异常登出!");
		ctx.close();
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		CmppPDU pdu = (CmppPDU) msg;

		SocketChannel ch = (SocketChannel) ctx.channel();
		
		InetSocketAddress inetSocketAddress = ch.remoteAddress();
		
		CmppServerHandler csh = (CmppServerHandler) ctx.handler();
		
		try {

			switch (pdu.getCommandId()) {
			case CmppConstant.CMD_SUBMIT: {
				String clientId = csh.clientId;
				Submit req = (Submit) pdu;
				logger.info("---------------------------------------------------------");
				String srcId = req.getSrcId();
				String[] destTermid = req.getDestTermId();
				String submitMsg = req.getMsgContent();
				
				logger.info(String.format("<%s> %s:<%s => %s> %s", clientId, req.name(), srcId,
						StringUtils.join(destTermid, ','), submitMsg));
				// 接收到的数据入队列
//				String respMsgid = UtilsUtils.getRandomId(7);
				String respMsgid = new SimpleDateFormat("MMddHHmmss").format(new Date()).toString();
				clientId  = respMsgid+","+clientId;
				NettyCommandHandler.saveSubmit2RedisQueue(req, clientId);
				cmpp.pdu.SubmitResp resp = (cmpp.pdu.SubmitResp) req.getResponse();
				resp.setResult(0);
				resp.setMsgId(respMsgid.getBytes());
				
				logger.info(String.format("<%s> %s", clientId, resp.name()));
				logger.info("submitResp response"+resp.dump());
				logger.info("---------------------------------------------------------");
				ctx.writeAndFlush(resp);
				break;
			}
			case CmppConstant.CMD_ACTIVE_TEST: {
				ActiveTest req = (ActiveTest) pdu;
				logger.info(String.format("<%s> %s", clientId, req.name()));

				cmpp.pdu.ActiveTestResp resp = (cmpp.pdu.ActiveTestResp) req.getResponse();
				logger.info(String.format("<%s> %s", clientId, resp.name()));

				ctx.writeAndFlush(resp);

				break;
			}

			case CmppConstant.CMD_QUERY: {
				Query req = (Query) pdu;
				logger.info(String.format("<%s> %s", clientId, req.name()));

				cmpp.pdu.QueryResp resp = (cmpp.pdu.QueryResp) req.getResponse();
				logger.info(String.format("<%s> %s", clientId, resp.name()));

				ctx.writeAndFlush(resp);
				break;
			}

			case CmppConstant.CMD_CANCEL: {
				Cancel req = (Cancel) pdu;
				logger.info(String.format("<%s> %s", clientId, req.name()));

				cmpp.pdu.CancelResp resp = (cmpp.pdu.CancelResp) req.getResponse();
				logger.info(String.format("<%s> %s", clientId, resp.name()));

				ctx.writeAndFlush(resp);
				break;
			}

			case CmppConstant.CMD_DELIVER: {
				Deliver req = (Deliver) pdu;
				logger.info(String.format("<%s> %s", clientId, req.name()));

				cmpp.pdu.DeliverResp resp = (cmpp.pdu.DeliverResp) req.getResponse();
				logger.info(String.format("<%s> %s", clientId, resp.name()));

				ctx.writeAndFlush(resp);
				break;
			}
			/**
			 * 1，IP鉴权 2，账号密码验证 3，同一账号，同一鉴权ip不可以多次登陆
			 */
			case CmppConstant.CMD_CONNECT: {
				String loginip = inetSocketAddress.getHostString();
				Connect req = (Connect) pdu;
				clientId = req.getClientId();
				logger.info(String.format("<%s> %s :-D ", clientId, req.name()));

				cmpp.pdu.ConnectResp resp = (cmpp.pdu.ConnectResp) req.getResponse();
				logger.info(String.format("<%s> %s", clientId, resp.name()));

					// 不需要做ip验证
				socketChannelMap.add(clientId, ch);
				ctx.writeAndFlush(resp);
				break;

			}
//			case CmppConstant.CMD_CONNECT: {
//				String loginip = inetSocketAddress.getHostString();
//				Connect req = (Connect) pdu;
//				clientId = req.getClientId();
//				logger.info(String.format("<%s> %s :-D ", clientId, req.name()));
//				
//				cmpp.pdu.ConnectResp resp = (cmpp.pdu.ConnectResp) req.getResponse();
//				logger.info(String.format("<%s> %s", clientId, resp.name()));
//				
//				ApiDownstream ads = (ApiDownstream) Redis.use("SGIP").get("apiDownstream_" + clientId);
//				String customerip = null;
//				if (ads != null) {
//					customerip = ads.getStr("IP");
//				}
//				// 需要鉴权ip通过
//				if (customerip != null && !"".equals(customerip)) {
//					logger.info("客户:" + clientId + "使用IP:" + loginip + "登录");
//					// 验证通过
//					if (customerip.contains(loginip)) {
//						// 是否存在登陆
//						// 否
//						if (socketChannelMap.get(clientId) == null) {
//							boolean authBoolean = ClientValidateUtil.authenticateClient(req.getAuthClient(), req);
//							if (!authBoolean) {
//								logger.info("客户:" + clientId + "密码错误。请核对");
//								resp.setStatus(3);
//							} else {
//								logger.info("客户:" + clientId + "登录成功。");
//								socketChannelMap.add(clientId, ch);
//							}
//							
//						} else {
//							logger.info("客户:" + clientId + "已登录。请登出后再登录!");
//							// 断开连接
//							resp.setStatus(2);
//						}
//						
//					} else {
//						logger.info("客户:" + clientId + "鉴权失败。绑定ip为：" + customerip);
//						// 断开连接
//						resp.setStatus(2);
//					}
//					
//					// 不需要做ip验证
//				} else {// 判断该是否登陆过
//					if (socketChannelMap.get(clientId) == null) {
//						boolean authBoolean = ClientValidateUtil.authenticateClient(req.getAuthClient(), req);
//						if (!authBoolean) {
//							logger.info("客户:"+clientId +"密码错误。请核对");
//							resp.setStatus(3);
//						}else{
//							logger.info("客户:"+clientId +"登录成功。");
//							socketChannelMap.add(clientId, ch);
//						}
//					} else {
//						logger.info("客户:"+clientId +"已登录。请登出后再登录!");
//						resp.setStatus(2);
//					}
//				}
//				
//				ctx.writeAndFlush(resp);
//				break;
//				
//			}

			case CmppConstant.CMD_TERMINATE: {
				String loginip = inetSocketAddress.getHostString();
				Terminate req = (Terminate) pdu;
				logger.info(String.format("<%s> %s", clientId, req.name()));

				if (!ctx.isRemoved()) {
					cmpp.pdu.TerminateResp resp = (cmpp.pdu.TerminateResp) req.getResponse();
					logger.info(String.format("<%s> %s", clientId, resp.name()));
					ctx.writeAndFlush(resp);
				}

				socketChannelMap.remove((SocketChannel) ctx.channel());
				logger.info("客户:" + clientId + "从" + loginip+"登出!");
				ctx.close();
				break;
			}

			default:
				// logger.error("Unknown Command! PDU Header: "+
				// pduHeader.getData().getHexDump());
				break;
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			ReferenceCountUtil.release(msg);
		}

	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		super.exceptionCaught(ctx, cause);
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
			IdleStateEvent event = (IdleStateEvent) evt;
			if (event.state() == IdleState.READER_IDLE)
				System.out.println("read idle");
			else if (event.state() == IdleState.WRITER_IDLE)
				System.out.println("write idle");
			else if (event.state() == IdleState.ALL_IDLE) {
				System.out.println(String.format("%d 秒过去了，客户<%s>杳无音信，＼(￣O￣) ...不伺候了", CmppServer.allIdleTime, clientId,
						CmppServer.allIdleTime));
				ctx.close();
				socketChannelMap.remove((SocketChannel) ctx.channel());
				logger.info("客户:" + clientId + "异常登出!");
				System.out.println(String.format("已关闭客户<%s>的连接", clientId));
			}

		}
	}
}
